package server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class IDFtpListener
{
	public static int ERR_CLOSING = -1;
	public static int ERR_CANT_BIND_PORT = -2;
	
	private int port = 21;
	private boolean running = false;
	private boolean autoIncrement = true;
	
	private ServerSocket svSock = null;
	private IDInstance env = null;
	
	transient private ArrayList<IDFtpThread> myThreads = new ArrayList<IDFtpThread>();
	private int maxThreads = 16; 
	
	private IDServerListener listener = null;
	
	public IDFtpListener(IDInstance inst, int port)
	{
		this.port = port;
		this.env = inst;
	}
	
	public IDFtpListener(IDInstance inst)
	{
		env = inst;
	}
	
	public void setServerListener(IDServerListener l)
	{
		listener = l;
	}
	
	protected IDServerListener getServerListener()
	{
		return listener;
	}
	
	public boolean isRunning()
	{
		return running;
	}
	
	public int getPort()
	{
		return isRunning() ? port : -1;
	}
	
	public void setAutoIncrement(boolean ai)
	{
		autoIncrement = ai;
	}
	
	public boolean isAutoIncrement()
	{
		return autoIncrement;
	}
	
	public void setMaxThreads(int m)
	{
		maxThreads = m;
		if(maxThreads < 1) maxThreads = 1;
		if(maxThreads > 128) maxThreads = 128;
	}
	
	public int getMaxThreads()
	{
		return maxThreads;
	}
	
	public void stopListening()
	{
		running = false;
	}
	
	public int startListening()
	{
		if(isRunning()) return port;
		
		if(svSock != null)
		{
			try 
			{
				svSock.close();
			} 
			catch (IOException e) 
			{
				System.out.println("Error in closing previous socket.");
				return ERR_CLOSING;
			}
			svSock = null;
		}
		
		int tries = 100;
		
		while(true)
		{
			try 
			{
				svSock = new ServerSocket(port);
				break;
			} 
			catch (IOException e) 
			{
				if(autoIncrement)
				{
					tries--;
					if(tries > 0)
					{
						port++;
						continue;
					}
					else
					{
						System.out.println("Can't bind port");
						return ERR_CANT_BIND_PORT;
					}
				}
				else
				{
					System.out.println("Can't bind port");
					return ERR_CANT_BIND_PORT;
				}
			}
		}
		
		//System.out.println("IP : " + svSock.getInetAddress().toString());
		
		running = true;
		
		while(running)
		{
			try 
			{
				Socket remote = svSock.accept();
				if(myThreads.size() < maxThreads)
				{
					IDFtpThread thread = new IDFtpThread(remote, env, this);
					myThreads.add(thread);
					thread.startThread();
				}
				else
				{
					//TODO present a page
					System.out.println("Overflow!");
					remote.close();
				}
			} 
			catch (IOException e) 
			{
				System.out.println("Error accepting connection?");
			}
		}
		
		return port;
	}
	
	protected void unregisterThread(IDFtpThread t)
	{
		myThreads.remove(t);
	}
}
